package sv.com.administrador.seguros.dao;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import sv.com.administrador.seguros.dto.ctg.CtgCatalogo;
import sv.com.administrador.seguros.exception.WebException;
import sv.com.administrador.seguros.web.util.WebUtility;

@Repository
public class BaseDaoImpl implements BaseDao {
	private static final String SAVE = "save";
	private static final String UPDATE = "update";
	private static final String DELETE = "delete";
	public static final Logger logger = Logger.getLogger(BaseDaoImpl.class);
	
	@Resource
	private JdbcTemplate jdbcTemplate;
	
	@Resource
	private HibernateTemplate hibernateTemplate;
	

	public HibernateTemplate getHibernateTemplate() {
		return hibernateTemplate;
	}

	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}

	@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class, WebException.class})
	private void trx(Object object, String operation) throws WebException {
		try {
			WebUtility.preProcessBeforeSaveOrUpdate(object, getHibernateTemplate().getSessionFactory());
			if ("save".equals(operation)) {
				if (object instanceof CtgCatalogo) {
					CtgCatalogo ctgCatalogo = (CtgCatalogo) object;
					if (ctgCatalogo.getCtgCatalogoId() == null) {
						ctgCatalogo.setCtgCatalogoHijo("00000");
						getHibernateTemplate().save(ctgCatalogo);
						ctgCatalogo.setCtgCatalogoHijo(StringUtils.leftPad(ctgCatalogo.getCtgCatalogoId().toString(), 5, "0"));
					}
					getHibernateTemplate().saveOrUpdate(ctgCatalogo);
				}
				else getHibernateTemplate().saveOrUpdate(object);
			}
			else if ("update".equals(operation)) getHibernateTemplate().update(object);
			else if ("delete".equals(operation)) getHibernateTemplate().delete(object);
		}catch (WebException e) {
			throw e;
		}catch (Exception e) {
			logger.error(e, e);
			throw new WebException(WebUtility.DEFAULT_ERROR_MESSAGE);
		}
	}

	public void save(Object object) throws WebException {
		trx(object, SAVE);
	}

	public void update(Object object) throws WebException {
		trx(object, UPDATE);
	}

	public void delete(Object object) throws WebException {
		trx(object, DELETE);
	}

	public void saveOrUpdateAll(List<?> objectList) throws WebException {
		for (Object object : objectList) save(object);
	}

	public void deleteAll(List<?> objectList) throws WebException {
		for (Object object : objectList) delete(object);
	}

	public Object findById(Class<?> entityClass, Long entityId) throws WebException {
		Object object = null;
		try {
			object = getHibernateTemplate().get(entityClass, entityId);
		}
		catch (Exception e) {
			String message = "No se pudo ejecutar consulta";
			logger.error(e, e);
			throw new WebException(message);
		}
		return object;
	}

	public List<?> findByCriteria(DetachedCriteria criteria) throws WebException {
		List<?> items = Collections.emptyList();
		try {
			items = getHibernateTemplate().findByCriteria(criteria);
		}
		catch (Exception e) {
			String message = "No se pudo ejecutar consulta";
			logger.error(e, e);
			throw new WebException(message);
		}
		return items;
	}

	public List<?> findByHQLQuery(String hqlQuery, Object[] values) throws WebException {
		List<?> items = Collections.emptyList();
		try {
			items = getHibernateTemplate().find(hqlQuery, values);
		}
		catch (Exception e) {
			String message = "No se pudo ejecutar consulta";
			logger.error(e, e);
			throw new WebException(message);
		}
		return items;
	}

	public List<?> findBySQLQuery(String sqlQuery, Object[] values) throws WebException {
		List<?> items = Collections.emptyList();
		try {
			items = getJdbcTemplate().queryForList(sqlQuery, values);
		}
		catch (Exception e) {
			String message = "No se pudo ejecutar consulta";
			logger.error(e, e);
			throw new WebException(message);
		}
		return items;
	}

	public void executeNonHibernateQuery(String hqlQuery, Map<String, Object> parameters) throws WebException {
		try {
			Query query = getHibernateTemplate().getSessionFactory().getCurrentSession().createQuery(hqlQuery);
			for (Entry<String, Object> entry : parameters.entrySet()){
				if(entry.getValue() instanceof Collection)
					query.setParameterList(entry.getKey(), (Collection<?>) entry.getValue());
				else
					query.setParameter(entry.getKey(), entry.getValue());
			}
			query.executeUpdate();
		}
		catch (Exception e) {
			String message = "No se pudo ejecutar consulta";
			logger.error(e, e);
			throw new WebException(message);
		}
	}

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}


	public void updateAll(List<?> objectList) throws WebException {
		for (Object object : objectList) update(object);
	}
}
